package gui.mainWindow.scores;

import gui.mainWindow.MainWindow;

import java.sql.SQLException;
import java.util.LinkedList;
import java.util.Observable;
import java.util.Observer;

import javax.swing.ComboBoxModel;
import javax.swing.DefaultComboBoxModel;

import tournamentData.Target;
import tournamentData.TournamentData;
import core.GuiComponentLabels;
import core.Person;
import dataBase.DbHolder;

public class ScoresController implements Observer {
	private final MainWindow window;
	private boolean saveImmediately = true;

	public ScoresController(MainWindow mainWindow) {
		this.window = mainWindow;
		DbHolder.getInstance().getArcherData().addObserver(this);
		TournamentData.getInstance().addObserver(this);
		TournamentData.getInstance().getTargetAssignment().addObserver(this);
	}

	/**
	 * @param playerID
	 *            the player id
	 * @return the players name + surname, separated by a whitespace
	 */
	private String getFullParticipantName(int playerID) {
		Person player = DbHolder.getInstance().getArcherData().getById(playerID);
		return player.getName() + " " + player.getSurName();
	}

	/**
	 * inserts all players into the dropdown menu, who have a target assigned
	 */
	public void buildParticipantsNameDropDown() {
		LinkedList < Integer > tmp = new LinkedList < Integer >();

		for (int i = 0; i < TournamentData.getInstance().getAllParticipants().length; i++) {
			if (TournamentData.getInstance().getTargetAssignment().hasTargetAssigned(TournamentData.getInstance().getAllParticipants() [i])) {
				tmp.add(TournamentData.getInstance().getAllParticipants() [i]);
			}
		}

		String [] participantNames = new String [tmp.size()];
		for (int i = 0; i < participantNames.length; i++) {
			participantNames [i] = this.getFullParticipantName(tmp.removeFirst());
		}
		ComboBoxModel participantNameDropDownModel = new DefaultComboBoxModel(participantNames);
		this.window.getScoresParticipantNameDropDown().setModel(participantNameDropDownModel);
		this.setDetailledArcherInformation();
	}

	/**
	 * display detailled information about the selected participant, based on
	 * the target selected
	 */
	public void setDetailledArcherInformation() {
		try {
			int selectedPlayerID = TournamentData.getInstance().getTargetAssignment().getPlayerForTarget(new Target(this.getSelectedTargetNumber(), this.getSelectedTargetChar()));
			Person selectedPlayer = DbHolder.getInstance().getArcherData().getById(selectedPlayerID);
			this.window.getScoresParticipantClubLabel().setText(selectedPlayer.getClub());
			this.window.getScoresParticipantBowCathegoryLabel().setText(selectedPlayer.getBowCathegory());
			this.window.getScoresParticipantAgeClassLabel().setText(selectedPlayer.getAgeClass());
		} catch (Exception e) {
			this.window.getScoresParticipantClubLabel().setText("-");
			this.window.getScoresParticipantBowCathegoryLabel().setText("-");
			this.window.getScoresParticipantAgeClassLabel().setText("-");
		}
	}

	@Override
	public void update(Observable arg0, Object arg1) {
		if (arg1 instanceof ScoresController) {

		} else {
			this.buildParticipantsNameDropDown();
			this.buildTargetDropDowns();
		}

	}

	/**
	 * inserts all target numbers into the dropdown menu, who have a target
	 * positions assigned
	 */
	public void buildTargetNumberDropDown() {
		LinkedList < Integer > tmp = new LinkedList < Integer >();
		for (int i = 1; i <= TournamentData.getInstance().getNumberOfTargets(); i++) {
			if (TournamentData.getInstance().getTargetAssignment().hasPlacesAssigned(i)) {
				tmp.add(i);
			}
		}
		Integer [] toAdd = new Integer [tmp.size()];
		for (int i = 0; i < toAdd.length; i++) {
			toAdd [i] = tmp.removeFirst();
		}

		ComboBoxModel scoresTargetNumberDropDownModel = new DefaultComboBoxModel(toAdd);

		this.window.getScoresTargetNumberDropDown().setModel(scoresTargetNumberDropDownModel);
	}

	/**
	 * inserts all targets positions into the dropdown menu which are assigned
	 * to the already selected target number
	 */
	public void buildTargetCharDropDown() {
		LinkedList < Character > tmp = new LinkedList < Character >();

		for (int i = 0; i < TournamentData.getInstance().getPlayersPerTarget(); i++) {
			if (TournamentData.getInstance().getTargetAssignment().hasPlayerAssigned(new Target(this.getSelectedTargetNumber(), (char) ('A' + i)))) {
				tmp.add((char) ('A' + i));
			}
		}

		Character [] toAdd = new Character [tmp.size()];
		for (int i = 0; i < toAdd.length; i++) {
			toAdd [i] = tmp.removeFirst();
		}

		ComboBoxModel scoresTargetCharDropDownModel = new DefaultComboBoxModel(toAdd);

		this.window.getScoresTargetCharDropDown().setModel(scoresTargetCharDropDownModel);
	}

	/**
	 * concatenating buildTargetNumberDropDown and buildTargetCharDropDown
	 */
	public void buildTargetDropDowns() {
		this.buildTargetNumberDropDown();
		this.buildTargetCharDropDown();
	}

	/**
	 * @return the number selected in the target number dropdown menu
	 */
	private int getSelectedTargetNumber() {
		if (this.window.getScoresTargetNumberDropDown().getItemCount() > 0) {
			return Integer.parseInt(this.window.getScoresTargetNumberDropDown().getSelectedItem().toString());
		}
		return 0;
	}

	/**
	 * @return the char selected in the target char dropdown menu
	 */
	private char getSelectedTargetChar() {
		if (this.window.getScoresTargetCharDropDown().getItemCount() > 0) {
			return this.window.getScoresTargetCharDropDown().getSelectedItem().toString().charAt(0);
		}
		return 'A';
	}

	/**
	 * set the player selected who is assigned to the selected target + position
	 */
	public void setAccordingPlayerSelected() {
		int playerID = TournamentData.getInstance().getTargetAssignment().getPlayerForTarget(new Target(this.getSelectedTargetNumber(), this.getSelectedTargetChar()));
		this.window.getScoresParticipantNameDropDown().setSelectedItem(this.getFullParticipantName(playerID));
	}

	/**
	 * @return the selected player's name
	 */
	private String getSelectedPlayerName() {
		return this.window.getScoresParticipantNameDropDown().getSelectedItem().toString();
	}

	/**
	 * set the target + place selected which is linked to the selected player
	 */
	public void setAccordingTargetSelected() {
		String selectedPlayer = this.getSelectedPlayerName();
		int index = 0;

		for (index = 0; index < TournamentData.getInstance().getAllParticipants().length; index++) {
			String currentlyScannedPlayer = this.getFullParticipantName(TournamentData.getInstance().getAllParticipants() [index]);
			if (selectedPlayer.equals(currentlyScannedPlayer)) {
				break;
			}
		}
		Target accordingTarget = TournamentData.getInstance().getTargetAssignment().getTargetForPlayer(TournamentData.getInstance().getAllParticipants() [index]);
		this.window.getScoresTargetNumberDropDown().setSelectedItem(accordingTarget.getNumber());
		this.window.getScoresTargetCharDropDown().setSelectedItem(accordingTarget.getCharacter());
	}

	/**
	 * builds the scores table according to the selected targetnumber + position
	 * @throws SQLException
	 */
	public void buildScoresTable() throws SQLException {
		int playerID = TournamentData.getInstance().getTargetAssignment().getPlayerForTarget(new Target(this.getSelectedTargetNumber(), this.getSelectedTargetChar()));

		if (playerID > 0) {
			ScoresTableModel model = new ScoresTableModel();

			Person player = DbHolder.getInstance().getArcherData().getById(playerID);

			String tournamentType = TournamentData.getInstance().getGeneralTournamentInformation().getTournamentType();
			String bowCathegory = player.getBowCathegory();
			String ageClass = player.getAgeClass();
			String gender = player.getGender();

			int numberOfRounds = DbHolder.getInstance().getArcherData().getNumberOfRounds(tournamentType, bowCathegory, ageClass, gender);

			for (int i = 1; i <= numberOfRounds; i++) {
				model.addRow(TournamentData.getInstance().getScore(playerID).getScoreAsArray(i));
			}

			int totalNines = TournamentData.getInstance().getScore(playerID).getTotalNines();
			int totalTens = TournamentData.getInstance().getScore(playerID).getTotalTens();
			int totalXs = TournamentData.getInstance().getScore(playerID).getTotalXS();
			int totalPoints = TournamentData.getInstance().getScore(playerID).getTotalPoints();

			model.addRow(new Object [] { GuiComponentLabels.TOTAL, totalPoints, totalTens, totalNines, totalXs });

			this.window.getScoresTable().setModel(model);
			this.window.getScoresTable().setRowSelectionInterval(0, 0);
			this.window.getScoresTable().setColumnSelectionInterval(1, 1);
		}
	}

	public void saveScore() {

		int playerID = TournamentData.getInstance().getTargetAssignment().getPlayerForTarget(new Target(this.getSelectedTargetNumber(), this.getSelectedTargetChar()));
		for (int i = 0; i < (this.window.getScoresTable().getRowCount() - 1); i++) {
			int round = Integer.parseInt(this.window.getScoresTable().getValueAt(i, 0).toString());

			int points = Integer.parseInt(this.window.getScoresTable().getValueAt(i, 1).toString());

			int tens = Integer.parseInt(this.window.getScoresTable().getValueAt(i, 2).toString());

			int nines = Integer.parseInt(this.window.getScoresTable().getValueAt(i, 3).toString());

			int hits = Integer.parseInt(this.window.getScoresTable().getValueAt(i, 4).toString());

			TournamentData.getInstance().getScore(playerID).setNines(round, nines);
			TournamentData.getInstance().getScore(playerID).setTens(round, tens);
			TournamentData.getInstance().getScore(playerID).setHits(round, hits);
			TournamentData.getInstance().getScore(playerID).setPoints(round, points);
		}
		this.updateScoreSum();
		TournamentData.getInstance().notifyOfScoreChange(this);
	}

	public void updateScoreSum() {
		int playerID = TournamentData.getInstance().getTargetAssignment().getPlayerForTarget(new Target(this.getSelectedTargetNumber(), this.getSelectedTargetChar()));
		int lastRow = this.window.getScoresTable().getRowCount() - 1;

		int totalPoints = TournamentData.getInstance().getScore(playerID).getTotalPoints();
		this.window.getScoresTable().setValueAt(totalPoints, lastRow, 1);

		int totalTens = TournamentData.getInstance().getScore(playerID).getTotalTens();
		this.window.getScoresTable().setValueAt(totalTens, lastRow, 2);

		int totalNines = TournamentData.getInstance().getScore(playerID).getTotalNines();
		this.window.getScoresTable().setValueAt(totalNines, lastRow, 3);

		int totalHits = TournamentData.getInstance().getScore(playerID).getTotalXS();
		this.window.getScoresTable().setValueAt(totalHits, lastRow, 4);
	}

	public void switchToNextPlayer() {
		int selectedRow = this.window.getScoresTable().getSelectedRow() - 1;

		/** if it is not the last target position selected */
		if (this.window.getScoresTargetCharDropDown().getSelectedIndex() < (this.window.getScoresTargetCharDropDown().getItemCount() - 1)) {
			/* switch to next target position */
			this.window.getScoresTargetCharDropDown().setSelectedIndex(this.window.getScoresTargetCharDropDown().getSelectedIndex() + 1);
			try {
				this.window.getScoresTable().setRowSelectionInterval(selectedRow, selectedRow);
			} catch (Exception e) {
				this.window.getScoresTable().setRowSelectionInterval(0, 0);
			}
		}
		/** if it is the last target position, but not the last target */
		else if (this.window.getScoresTargetNumberDropDown().getSelectedIndex() < (this.window.getScoresTargetNumberDropDown().getItemCount() - 1)) {
			/* switch to next target and first target position */
			this.window.getScoresTargetNumberDropDown().setSelectedIndex(this.window.getScoresTargetNumberDropDown().getSelectedIndex() + 1);
			this.window.getScoresTargetCharDropDown().setSelectedIndex(0);
			try {
				this.window.getScoresTable().setRowSelectionInterval(selectedRow, selectedRow);
			} catch (Exception e) {
				this.window.getScoresTable().setRowSelectionInterval(0, 0);
			}
		}
		/** if it is the last target AND last position */
		else {
			/* switch to the first target and -position */
			this.window.getScoresTargetNumberDropDown().setSelectedIndex(0);
			this.window.getScoresTargetCharDropDown().setSelectedIndex(0);

			/* switch to the next row in the table */

			int oneRowTooFar = this.window.getScoresTable().getRowCount() - 1;
			int newIndex = (selectedRow + 1) % oneRowTooFar;
			try {
				this.window.getScoresTable().setRowSelectionInterval(newIndex, newIndex);
			} catch (Exception e) {
				this.window.getScoresTable().setRowSelectionInterval(0, 0);
			}

		}
		this.window.getScoresTable().setColumnSelectionInterval(1, 1);
	}

	public void setSaveImmediately(boolean selected) {
		this.saveImmediately = selected;
	}

	public boolean isSaveImmediately() {
		return this.saveImmediately;
	}
}
